use crate::pipeline::{prepare_billboard_bind_group, prepare_billboard_view_bind_groups, queue_billboard_texture, BillboardImageBindGroups, BillboardPipeline, BillboardUniform, DrawBillboard};
use crate::text::{
    detect_billboard_text_color_change, extract_billboard_text, update_billboard_text_layout,
    BillboardTextHandles,
};
use crate::texture::extract_billboard_texture;
use crate::{prelude::*, Billboard, ConstantScreenSizeBillboard, BILLBOARD_SHADER_HANDLE};
use bevy::prelude::*;
use bevy::render::camera::CameraUpdateSystems;
use bevy::render::extract_component::{ExtractComponentPlugin, UniformComponentPlugin};
use bevy::render::render_phase::AddRenderCommand;
use bevy::render::render_resource::SpecializedMeshPipelines;
use bevy::render::view::check_visibility;
use bevy::render::{RenderApp, RenderSet};
use bevy::text::detect_text_needs_rerender;
use bevy::window::PrimaryWindow;
use bevy::{asset::load_internal_asset, core_pipeline::core_3d::Transparent3d, render::Render};

pub struct BillboardPlugin;

impl Plugin for BillboardPlugin {
    fn build(&self, app: &mut App) {
        load_internal_asset!(
            app,
            BILLBOARD_SHADER_HANDLE,
            "shader/billboard.wgsl",
            Shader::from_wgsl
        );

        app.add_plugins(UniformComponentPlugin::<BillboardUniform>::default())
            .add_plugins(ExtractComponentPlugin::<Billboard>::default())
            .register_type::<BillboardMesh>()
            .register_type::<BillboardTexture>()
            .register_type::<BillboardTextBounds>()
            .register_type::<BillboardTextHandles>()
            .add_systems(
                PostUpdate,
                (
                    (
                        (
                            detect_text_needs_rerender::<BillboardText>,
                            detect_billboard_text_color_change,
                        ),
                        update_billboard_text_layout,
                    )
                        .chain()
                        .ambiguous_with(CameraUpdateSystems),
                ),
            )
            .add_systems(PreUpdate, (update_billboard_transform, /* update_billboard_scale */)); //update_billboard_scale
    }

    fn finish(&self, app: &mut App) {
        app.sub_app_mut(RenderApp)
            .add_render_command::<Transparent3d, DrawBillboard>()
            .init_resource::<BillboardPipeline>()
            .init_resource::<SpecializedMeshPipelines<BillboardPipeline>>()
            .init_resource::<BillboardImageBindGroups>()
            .add_systems(
                ExtractSchedule,
                (extract_billboard_text, extract_billboard_texture),
            )
            .add_systems(Render, queue_billboard_texture.in_set(RenderSet::Queue))
            .add_systems(
                Render,
                prepare_billboard_bind_group.in_set(RenderSet::PrepareBindGroups),
            )
            .add_systems(
                Render,
                prepare_billboard_view_bind_groups.in_set(RenderSet::PrepareBindGroups),
            );
    }
}



// 更新系统，使 billboard 始终面向相机
fn update_billboard_transform(
    camera_query: Query<&GlobalTransform, With<Camera>>,
    mut billboard_query: Query<&mut Transform, With<Billboard>>,
) {
    // 获取相机的变换信息
    let camera_transform = match camera_query.single() {
        Ok(transform) => transform,
        Err(_) => return, // 如果没有相机，跳过更新
    };

    // 计算相机的视图矩阵（逆矩阵）
    let view_matrix = camera_transform.compute_matrix().inverse();

    // 从视图矩阵中提取旋转部分并转置
    let rotation = Mat3::from_mat4(view_matrix).transpose();

    // 更新所有 billboard 的旋转
    for mut transform in billboard_query.iter_mut() {
        // 只更新旋转，保持位置和缩放不变
        transform.rotation = Quat::from_mat3(&rotation);
    }
}

fn update_billboard_scale(
    mut query: Query<(&mut Transform, &ConstantScreenSizeBillboard), (With<Billboard>, Without<BillboardAttachedCamera>)>,
    camera_query: Query<(&Transform, &Projection), With<BillboardAttachedCamera>>,
    windows: Query<&Window, With<PrimaryWindow>>,
) {
    let (camera_transform, projection) = camera_query.single().unwrap();
    let projection = match projection {
        Projection::Perspective(projection) => projection,
        _ => return,
    };
    let fov_deg = projection.fov;
    let fov_rad = fov_deg.to_radians();
    let tan_half_fov = fov_rad.tan() / 2.0;
    let window = windows.single().unwrap();
    let window_height_pixels = window.height() as f32;
    // 获取摄像机的前向量（朝向）
    let camera_forward = camera_transform.forward().normalize();

    for (mut transform, billboard_component) in query.iter_mut() {
        let billboard_position = transform.translation;
        let camera_position = camera_transform.translation;
        let distance = (billboard_position - camera_position).length();

        // 计算广告牌到摄像机的方向向量
        let to_camera = (camera_position - billboard_position).normalize();

        // 计算摄像机朝向与广告牌方向的夹角余弦
        let cos_theta = camera_forward.dot(to_camera).abs().max(0.01); // 避免除以 0

        // 基础高度缩放（保持屏幕高度恒定）
        let screen_height_ratio = billboard_component.screen_height_ratio;
        let initial_world_height = billboard_component.initial_world_size;
        let desired_screen_height_pixels = window_height_pixels * screen_height_ratio;
        let k = desired_screen_height_pixels * 2.0 * tan_half_fov;
        let world_height = k * distance;
        let height_scale = world_height / initial_world_height;

        // 宽度缩放根据视角角度调整，保持宽高比
        // let aspect_ratio = billboard_component.aspect_ratio;
        let aspect_ratio = 1.0;
        let width_scale = height_scale * aspect_ratio * cos_theta;

        dbg!(width_scale, height_scale);

        // 应用缩放，z 轴保持 1.0（广告牌为平面）
        transform.scale = Vec3::new(width_scale, height_scale, 1.0);
    }
}